package cn.stu.framework.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ReUtil;
import cn.stu.common.exception.CustomException;
import cn.stu.common.utils.*;
import cn.stu.framework.dto.UserDisableDto;
import cn.stu.framework.dto.UsersDetailDto;
import cn.stu.framework.entity.Users;
import cn.stu.framework.entity.UsersDetail;
import cn.stu.framework.mapper.RoleMapper;
import cn.stu.framework.mapper.UsersDetailMapper;
import cn.stu.framework.mapper.UsersMapper;
import cn.stu.framework.service.UsersDetailService;
import cn.stu.framework.service.UsersService;
import cn.stu.framework.vo.UsersDetailVo;
import cn.stu.framework.vo.UsersVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

import static cn.stu.common.core.Constants.DOT_STAR;
import static cn.stu.common.utils.SystemConstants.IMAGE_USERS_DEFAULT_DIR;
import static cn.stu.common.utils.SystemConstants.LOGIN_USER_KEY;


/**
 * 实施用户详细信息服务
 *
 * @author 郑志豪
 * @date 2023/10/31
 */
@Service
@Log4j2
@AllArgsConstructor
public class UsersDetailServiceImpl extends ServiceImpl<UsersDetailMapper, UsersDetail> implements UsersDetailService {

    private UsersMapper usersMapper;

    private UsersService usersService;

    private RoleMapper roleMapper;

    private MinioTool minioTool;

    private StringRedisTemplate stringRedisTemplate;


    @Override
    public R<UsersVo> userInfo(Long userId) {
        UsersVo info = usersMapper.userMsg(userId);
        info.setUserImage(usersService.outImage(info.getUserImage()));
        return R.ok(info, "获取成功!");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiData userAdd(UsersDetailVo urs) {
        if (usersService.lambdaQuery().eq(Users::getAcc, urs.getAcc()).exists()) {
            return ApiData.getFalse("登录名已存在，请更换其他登录名！");
        }
        UsersDetail detail = BeanUtils.copier(urs, new UsersDetail());
        detail.setHireTime(MyTools.turnDate(urs.getHireTimes()));
        detail.setUserImage(IMAGE_USERS_DEFAULT_DIR);
        //md5加密
        String password = DigestUtils.md5DigestAsHex("123456".getBytes());
        //用户表数据
        Users users = BeanUtils.copier(urs, new Users());
        users.setPwd(password);
        usersMapper.insert(users);
        detail.setUserId(users.getUserId());
        baseMapper.insert(detail);
        return ApiData.getTrue("添加成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiData userDel(Long userId, String pwd) {
        Long updateId = UserHolder.getUser().getUserId();
        if (userId == null) {
            return ApiData.getFalse("id为空!");
        }
        if (CharSequenceUtil.isBlank(pwd)) {
            return ApiData.getFalse("密码错误!");
        }
        if (userId == 1) {
            return ApiData.getFalse("超管账户不允许操作!");
        }
        Users user = usersMapper.selectById(userId);
        if (user == null) {
            return ApiData.getFalse("用户不存在!");
        }
        Users updateUser = usersMapper.selectById(updateId);
        if (!updateUser.getPwd().equals(pwd)) {
            return ApiData.getFalse("密码错误!");
        }
        //用户表逻辑删除
        usersMapper.deleteById(userId);
        //用户详情表逻辑删除
        lambdaUpdate().eq(UsersDetail::getUserId, userId).remove();
        String tokenKey = LOGIN_USER_KEY + userId;
        stringRedisTemplate.delete(tokenKey);
        return ApiData.getTrue("删除成功!");
    }

    @Override
    public ApiData userReset(Long userId) {
        if (userId == null) {
            return ApiData.getFalse("id为空!");
        }
        if (userId == 1) {
            return ApiData.getFalse("超管不可进行此操作");
        }
        Users u = usersMapper.selectById(userId);
        if (u == null) {
            return ApiData.getFalse("id不存在!");
        }
        String resetPwd = MyTools.generatePassword(8);
        String password = DigestUtils.md5DigestAsHex(resetPwd.getBytes());
        usersService.lambdaUpdate().set(Users::getPwd, password)
                .eq(Users::getUserId, userId)
                .update();
        return ApiData.getTrue("重置成功，密码已经重置为" + resetPwd);
    }

    /**
     * 用户更新
     *
     * @param urs URS
     * @return {@link ApiData}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiData userUpdate(UsersDetailVo urs) {
        Users u = usersMapper.selectById(urs.getUserId());
        if (u == null) {
            return ApiData.getFalse("用户" + "不存在！");
        }
        if (!urs.getAcc().equals(u.getAcc())) {
            boolean exists = usersMapper.exists(usersService
                    .lambdaQuery()
                    .eq(Users::getAcc, urs.getAcc())
                    .ne(Users::getUserId, urs.getUserId())
                    .getWrapper());
            if (exists) {
                return ApiData.getFalse("账号已存在，请更换！");
            }
        }
        if (urs.getRoleId() != null && roleMapper.selectById(urs.getRoleId()) == null) {
            return ApiData.getFalse("此角色不存在！");
        }
        UsersDetail oldDetail = lambdaQuery().eq(UsersDetail::getUserId, urs.getUserId()).one();
        // 获取新头像URL
        String fileUrl = getNewFileUrl(urs, oldDetail, u);
        //详情表数据
        UsersDetail update = BeanUtils.copier(urs, new UsersDetail());
        update.setUserDetailId(oldDetail.getUserDetailId());
        if (urs.getHireTimes() != null) {
            update.setHireTime(MyTools.turnDate(urs.getHireTimes()));
        }
        update.setUserImage(fileUrl);
        //用户表数据
        Users updateUser = BeanUtils.copier(urs, new Users());
        updateUser.setUserId(urs.getUserId());
        if (urs.getRoleId() != null) {
            updateUser.setRoleId(urs.getRoleId());
        } else {
            updateUser.setRoleId(u.getRoleId());
        }
        usersMapper.updateById(updateUser);
        baseMapper.updateById(update);
        return ApiData.getTrue("修改成功");
    }

    /**
     * 获取新文件URL
     *
     * @param urs       Urs
     * @param oldDetail 旧细节
     * @param u         u
     * @return {@link String}
     */
    private String getNewFileUrl(UsersDetailVo urs, UsersDetail oldDetail, Users u) {
        if (ReUtil.isMatch(DOT_STAR + minioTool.avatarBucketName + DOT_STAR, urs.getUserImage())) {
            return null;
        }
        try {
            if (CharSequenceUtil.isNotBlank(oldDetail.getUserImage())) {
                String oldFilePath = extractFileName(oldDetail.getUserImage());
                //删除旧头像
                if (!oldDetail.getUserImage().equals(IMAGE_USERS_DEFAULT_DIR)) {
                    Boolean del = minioTool.removeBucketObject(minioTool.avatarBucketName, UserHolder.getUser().getUserId() + StrPool.SLASH + oldFilePath);
                    if (Boolean.FALSE.equals(del)) {
                        log.error("删除异常");
                    }
                }
            }
            String newFilePath = u.getUserId() + StrPool.SLASH + urs.getUserImage();
            //文件移动
            minioTool.bucketFileMove(minioTool.tempBucketName, urs.getUserImage(), minioTool.avatarBucketName, newFilePath);
            //获取头像地址
            return newFilePath;
        } catch (Exception e) {
            log.error(e);
            throw new CustomException("修改异常！");
        }
    }

    /**
     * selectContacts
     *
     * @param usersDetailDto 用户详细资料
     * @return {@link ApiData}
     */
    @Override
    public ApiData selectContacts(UsersDetailDto usersDetailDto) {
        Page<UsersDetailVo> page = new Page<>(usersDetailDto.getPage(), usersDetailDto.getLimit());
        baseMapper.getContacts(page, usersDetailDto.getDeptId(), usersDetailDto.getName(), usersDetailDto.getTel());
        List<UsersDetailVo> records = page.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            records.forEach(item -> item.setUserImage(usersService.outImage(item.getUserImage())));
        }
        return ApiData.getPageTrue("获取成功", page.getTotal(), records);
    }


    /**
     * 用户禁用
     *
     * @param userDisableDto 用户禁用dto
     * @return {@link ApiData}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiData userDisabled(UserDisableDto userDisableDto) {
        if (userDisableDto.getUserId() == null) {
            return ApiData.getFalse("id为空!");
        }
        if (userDisableDto.getUserId() == 1) {
            return ApiData.getFalse("超管账户不允许操作!");
        }
        Long userId = userDisableDto.getUserId();
        UsersVo user = usersMapper.userMsg(userId);
        if (user == null) {
            return ApiData.getFalse("用户不存在!");
        }
        if (!user.getAcc().equals(userDisableDto.getAcc()) || !user.getName().equals(userDisableDto.getName())) {
            return ApiData.getFalse("用户不存在!");
        }
        int disable = user.getIsDisable() == 0 ? 1 : 0;
        Users update = new Users();
        update.setUserId(userId);
        update.setIsDisable(disable);
        usersMapper.updateById(update);
        String tokenKey = LOGIN_USER_KEY + userId;
        stringRedisTemplate.delete(tokenKey);
        return ApiData.getTrue("账号" + user.getAcc() + (disable == 0 ? "启用" : "禁用") + "成功!");
    }

    @Override
    public R<List<UsersDetailVo>> selectUserList(UsersDetail usersDetail) {
        return R.ok(baseMapper.getUserList());
    }

    /**
     * 文件上传
     *
     * @param newImg 新img
     * @return {@link ApiData}
     */
    @Override
    public ApiData fileUpload(MultipartFile newImg) {
        if (newImg == null) {
            return ApiData.getFalse("无头像文件");
        }
        //获取UUID
        String id = UUID.randomUUID().toString(true);
        //获取文件名
        String originalFilename = newImg.getOriginalFilename();
        //重命名文件名
        String rename;
        if (originalFilename != null) {
            rename = id + originalFilename.substring(originalFilename.lastIndexOf("."));
        } else {
            return ApiData.getFalse("文件名后缀获取异常！");
        }
        Boolean upload = minioTool.upload(minioTool.tempBucketName, newImg, rename);
        if (Boolean.FALSE.equals(upload)) {
            return ApiData.getFalse("上传失败");
        }
        return ApiData.getTrue("上传成功", rename);
    }

    private static String extractFileName(String input) {
        // 查找文件名的起始位置和结束位置
        int startIndex = input.lastIndexOf(StrPool.SLASH) + 1;
        int endIndex = input.indexOf(".") + 4;
        // 提取文件名部分
        return input.substring(startIndex, endIndex);
    }


}
